/*
 * Copyright (C) Jahia Ltd. All rights reserved.
 *
 * This software is published under the terms of the Jahia Open Software
 * License version 1.1, a copy of which has been included with this
 * distribution in the LICENSE.txt file.
 */
package org.jahia.sqlprofiler;

import java.util.*;
import org.jahia.sqlparser.SqlLexer;
import java.io.*;
import org.jahia.sqlparser.SqlParser;
import antlr.collections.AST;
//import antlr.DumpASTVisitor;    //JPV : For debugging Tree
import org.jahia.sqlparser.SqlTreeParser;

/**
 * <p>Title: SQL Profiler</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2003</p>
 * <p>Company: Jahia Ltd</p>
 * @author Serge Huber
 * @author Jean-Philippe Valentin
 * @version 2.0
 *
 * 11/14/2003 : Add DML statements by Jean-Philippe VALENTIN (JPV)
 */

public class QueryStatistics {

    private static final org.apache.log4j.Logger logger = org.apache.log4j.
        Logger.getLogger(QueryStatistics.class);

    Map occurences = new TreeMap();
    Map queryStatEntries = new TreeMap();
    private long totalElapsedQueryTime = 0;

    public QueryStatistics() {

    }

    public void clear() {
        occurences.clear();
        queryStatEntries.clear();
        totalElapsedQueryTime = 0;
    }

/*JPV : Add DML statements*/
    public Integer processSQL(QueryEntry queryEntry) {
        Integer occurenceCount = null;
        String sqlStatement = queryEntry.getSqlStatement().toLowerCase();
        if (sqlStatement.trim().startsWith("select") ||
            sqlStatement.trim().startsWith("insert") ||
            sqlStatement.trim().startsWith("update") ||
            sqlStatement.trim().startsWith("delete")) {
            occurenceCount = (Integer) occurences.get(
                sqlStatement);
            if (occurenceCount == null) {
                occurenceCount = new Integer(0);
            }
            occurenceCount = new Integer(occurenceCount.intValue() + 1);
            occurences.put(sqlStatement, occurenceCount);
            parseSQL(queryEntry);
        }
        return occurenceCount;
    }

    public Set getQueryStatsByOccurence() {
        Set queryStatByOccurence = new TreeSet();
        Iterator queryStatIter = queryStatEntries.keySet().iterator();
        while (queryStatIter.hasNext()) {
            String curQueryStatKey = (String) queryStatIter.next();
            QueryStatEntry curQueryStatEntry = (QueryStatEntry)
                queryStatEntries.get(curQueryStatKey);
            queryStatByOccurence.add(curQueryStatEntry);
        }
        return queryStatByOccurence;
    }

    public Map getGeneratedIndexes() {
        Map generatedIndexes = new TreeMap();
        Iterator queryStatByOccurenceIter = getQueryStatsByOccurence().iterator();
        while (queryStatByOccurenceIter.hasNext()) {
            QueryStatEntry curQueryStat = (QueryStatEntry)
                queryStatByOccurenceIter.next();

            if ((curQueryStat.getTableNames().size() == 1) &&
                (curQueryStat.getColumnNames().size() > 0)) {
                // only generate index on one table for the moment.
                // first let's generate an index name
                String tableName = (String) curQueryStat.getTableNames().
                    iterator().next();
                if (tableName.startsWith("SEL_"))
                //JPV : only SELECT statements used by index generation
                {
                    //JPV : don't keep the prefix SEL_
                    tableName = tableName.substring(4, tableName.length());
                String indexName = tableName + "_index";
                String indexSuffix = "";
                int indexSuffixNumber = 1;
                while (generatedIndexes.containsKey(new String(indexName +
                    indexSuffix))) {
                    indexSuffixNumber++;
                    indexSuffix = Integer.toString(indexSuffixNumber);
                }
                StringBuffer indexStrBuffer = new StringBuffer(
                    "CREATE INDEX ");
                indexStrBuffer.append(indexName);
                indexStrBuffer.append(indexSuffix);
                indexStrBuffer.append(" ON ");
                indexStrBuffer.append(tableName);
                indexStrBuffer.append(" ( ");
                Iterator columnNameIter = curQueryStat.getColumnNames().
                    iterator();
                while (columnNameIter.hasNext()) {
                    String curColumnName = (String) columnNameIter.next();
                    indexStrBuffer.append(curColumnName);
                    if (columnNameIter.hasNext()) {
                        indexStrBuffer.append(",");
                    }
                }
                indexStrBuffer.append(" ); ");
                generatedIndexes.put(new String(indexName + indexSuffix),
                                     indexStrBuffer.toString());
            }
        }
        }
        return generatedIndexes;
    }

    private void parseSQL(QueryEntry queryEntry) {
        try {
            SqlLexer lexer = new SqlLexer(new StringReader(queryEntry.getSqlStatement().toLowerCase()));
            SqlParser parser = new SqlParser(lexer);
            parser.start_rule();
            AST resultTree = parser.getAST();

            /*
                         System.out.println("");
                         System.out.println("==> Dump of AST <==");
                         DumpASTVisitor visitor = new DumpASTVisitor();
                         visitor.visit(resultTree);
                         System.out.println("==> End Dump of AST <==");
             */

            SqlTreeParser sqlTreeParser = new SqlTreeParser();
/*JPV : Add DML statements*/
            String strSqlStatement = queryEntry.getSqlStatement().toLowerCase();
            if (strSqlStatement.trim().startsWith("select"))
            {
            sqlTreeParser.select_statement(resultTree);
            }
            else if (strSqlStatement.trim().startsWith("update"))
            {
                sqlTreeParser.update_command(resultTree);
            }
            else if (strSqlStatement.trim().startsWith("delete"))
            {
                sqlTreeParser.delete_command(resultTree);
            }
            else if (strSqlStatement.trim().startsWith("insert"))
            {
                sqlTreeParser.insert_command(resultTree);
            }

/*End JPV*/
            QueryStatEntry newEntry = new QueryStatEntry(sqlTreeParser.
                getTableNames(), sqlTreeParser.getColumnNames());
            if (queryStatEntries.containsKey(newEntry.getKey())) {
                newEntry = (QueryStatEntry) queryStatEntries.get(newEntry.
                    getKey());
            }
            newEntry.incOccurences();
            newEntry.addQuery(queryEntry);
            if (queryEntry.getElapsedTime() > 0) {
                newEntry.incTotalElapseTime(queryEntry.getElapsedTime());
                totalElapsedQueryTime += queryEntry.getElapsedTime();
            }
            queryStatEntries.put(newEntry.getKey(), newEntry);

        } catch (Exception e) {
            System.err.println("exception: " + e);
        }
    }

    public int getOccurenceCount() {
        return occurences.size();
    }

    public long getTotalElapsedQueryTime() {
        return totalElapsedQueryTime;
    }

}